package com.example.networkcore

import android.os.Environment
import com.example.common.BaseApp
import com.example.common.SPUtils
import com.example.networkcore.Interceptor.CacheInterceptor
import com.example.networkcore.api.TokenApi
import com.example.networkcore.common.Constant
import com.example.networkcore.retrofit.CustomGsonConverterFactory
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import java.io.File
import java.util.concurrent.TimeUnit

class RetrofitFactory private constructor(){
    val retrofit: Retrofit

    companion object{
        val instance:RetrofitFactory by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            RetrofitFactory()
        }
    }

    init {
        retrofit = Retrofit.Builder()
            .baseUrl(BuildConfig.BASEURL)
            .addConverterFactory(CustomGsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .client(createClient())
            .build()
    }

    /**
     * 创建Okhttp客户端
     */
    private fun createClient(): OkHttpClient  {
        return OkHttpClient.Builder()
            .cache(generateCache())//
            .readTimeout(Constant.TIMEOUT_TIMES, TimeUnit.SECONDS)
            .writeTimeout(Constant.TIMEOUT_TIMES, TimeUnit.SECONDS)
            .connectTimeout(Constant.TIMEOUT_TIMES, TimeUnit.SECONDS)
            .addNetworkInterceptor(createLogIntereptor())
            .addNetworkInterceptor(CacheInterceptor())//
            .addInterceptor(createTokenIntereptor())
            .addInterceptor(createMoreBaseUrlInterptor())//
            .build()
    }

    /**
     * 支持多BaseUrl拦截器
     */
    private fun createMoreBaseUrlInterptor(): Interceptor {
        return Interceptor {
            //从chain（it）拿到请求
            val request= it.request()

            //从请求上拿到所有请求头 但要以Constant.SERVER_PREFIX为可用的
            val header = request.headers().get(Constant.SERVER_PREFIX)
            //从已有请求中构建信息的请求builder
            val newRequestBuilder= request.newBuilder()
            //从已有请求获取url地址
            val oldUrl:HttpUrl= request.url()
            //从已有地址创建新地址的Builder
            val newUrlBuilder= oldUrl.newBuilder()

            //暂存最终地址的String
            var newUrlAddress:String = ""

            if (header!=null){
                //删除上面的请求头 因为没必要提交给后台 主要我们前端自己区分服务器地址用
                newRequestBuilder.removeHeader(Constant.SERVER_PREFIX)
                //根据不同的头value进行BaseUrl的选择
                when(header){
                    //电商后台
                    Constant.MALL_SERVER_VALUE->newUrlAddress=BuildConfig.BASEURL
                    //轮播图后台
                    Constant.BANNER_SERVER_VALUE->newUrlAddress=BuildConfig.BANNER_BASEURL
                    else->newUrlAddress=BuildConfig.BASEURL
                }
                //通过获取到的最终地址构建HttpUrl对象
                val httpUrl= HttpUrl.parse(newUrlAddress)
                //设置协议如：Http Https等WS
                newUrlBuilder.scheme(httpUrl?.scheme())
                //设置ip地址
                newUrlBuilder.host(httpUrl?.host())
                //设置端口
                newUrlBuilder.port(httpUrl?.port()!!)
            }
            //通过构建信息的HttpUrl也就是新请求地址从而构建新reqeust请求交给拦截器进行下一步处理
            it.proceed(newRequestBuilder.url(newUrlBuilder.build()).build())
        }
    }

    /**
     * 创建缓存
     */
    private fun generateCache(): Cache? {
        //设置缓存路径
        val file = File( Environment.getExternalStorageDirectory().absolutePath + File.separator+"test");
        if (!file.exists()){
            file.mkdirs()
        }
        //磁盘缓存所需大小
        val cacheSize:Long = 10 * 1024 * 1024;
        val cache = Cache(file, cacheSize);
        return cache
    }

    /**
     * 处理后台Token
     */
    private fun createTokenIntereptor(): Interceptor {
        val interceptor= Interceptor {

//            it.proceed(it.request())
            val request = it.request()
            var response: Response?

            val localToken = SPUtils.get(BaseApp.appContext, Constant.Token_KEY, "") as String
            if (localToken.isNotBlank()){
                response = doRequest(it, createNewRequest(request, localToken))
            }else{
                response = it.proceed(request)
            }
            if (check401(response!!)){
                requestNewToken(chain = it, request = request)
            }else{
                response
            }
        }

        return interceptor
    }

    /**
     * 请求新token处理
     */
    private fun requestNewToken(chain: Interceptor.Chain, request: Request): Response {
        val token = requestToken();
        val response = doRequest(chain, createNewRequest(request, token))
        SPUtils.put(BaseApp.appContext,Constant.Token_KEY,token)
        return response
    }

    private fun doRequest(chain: Interceptor.Chain, request: Request): Response {

        return chain.proceed(request)
    }

    /**
     * 添加头信息 携带并验证token
     */
    private fun createNewRequest(request: Request, token:String): Request {
        val newBuilder =
            request.newBuilder().addHeader("Authorization", "bearer $token")

        val newRequest = newBuilder.build()
        return newRequest
    }

    /**
     * 请求token
     */
    private fun requestToken():String {
        val tokenApi = create(TokenApi::class.java)
        val token = tokenApi.getToken("password", BuildConfig.VERIFYCODE, "")
        val result = token!!.execute()
        return result.body()?.getAccess_token()?:""
    }

    /**
     * token错误或者没有token处理
     */
    private fun check401(response: Response): Boolean {
        if (response.code()==401){
            return true
        }
        return false
    }

    /**
     * 日志拦截器
     */
    private fun createLogIntereptor(): Interceptor {
        var logInterceptor= HttpLoggingInterceptor()
        logInterceptor.level=HttpLoggingInterceptor.Level.BODY
        return logInterceptor
    }

    /**
     * 创建Api 实例
     */
    fun <T> create(service:Class<T>):T{
        return retrofit.create(service)
    }
}